package com.dream.kgbuilder.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.csvreader.CsvWriter;
import com.dream.core.config.DreamAppConfig;
import com.dream.core.core.domain.AjaxResult;
import com.dream.kgbuilder.openfeign.AuthUserFeignService;
import com.dream.web.controller.BaseController;
import com.dream.core.utils.DateUtils;
import com.dream.core.utils.R;
import com.dream.kgbuilder.utils.neo4j.Neo4jUtil;
import com.dream.web.utils.CSVUtil;
import com.dream.web.utils.ExcelUtil;
import com.dream.kgbuilder.domain.dto.GraphNode;
import com.dream.kgbuilder.domain.dto.GraphPageRecord;
import com.dream.kgbuilder.domain.dto.GraphQuery;
import com.dream.kgbuilder.service.KGGraphService;
import com.dream.kgbuilder.service.KnowledgeGraphService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.Charset;
import java.util.*;

@RestController
@RequestMapping(value = "/kg")
public class KGManagerController extends BaseController {
    @Autowired
    private Neo4jUtil neo4jUtil;
    @Autowired
    private KGGraphService kgGraphService;
    @Autowired
    private KnowledgeGraphService knowledgeGraphService;
    @Autowired
    AuthUserFeignService authUserFeignService;
    @ResponseBody
    @RequestMapping(value = "/getDataScope") // call db.labels
    public R getDataScope(int userId) {
        AjaxResult dataScope = authUserFeignService.getDataScope(userId);
        return R.success().put("data", dataScope.get("dataScope"));
    }
    @ResponseBody
    @RequestMapping(value = "/getDataJson") // call db.labels
    public R getDataJson() {
        Map<String,String> data=new HashMap<>();
        data.put("a1","a1");
        data.put("a2","a2");
        AjaxResult dataScope = authUserFeignService.addDataScope(data);
        return R.success().put("data", dataScope.get("dataScope"));
    }

    @ResponseBody
    @RequestMapping(value = "/getInfo") // call db.labels
    public R getInfo(HttpServletRequest request) {
        String tan = request.getHeader("tan");
        System.out.println(tan);
        return R.success().put("data", "dream-kgBuilder");
    }
    @ResponseBody
    @RequestMapping(value = "/getInfo2") // call db.labels
    public R getInfo2() {
        return R.success().put("data", "dream-kgBuilder2");
    }
    @ResponseBody
    @RequestMapping(value = "/getGraph") // call db.labels
    public R getGraph(GraphQuery queryItem) {
        GraphPageRecord<Map<String, Object>> dataItem = new GraphPageRecord<>();
        GraphPageRecord<Map<String, Object>> resultRecord = new GraphPageRecord<Map<String, Object>>();
        try {
            String name = "tc";
            PageHelper.startPage(queryItem.getPageIndex(), queryItem.getPageSize(), true);
            List<Map<String, Object>> domainList = knowledgeGraphService.getDomainList(queryItem.getDomain(), name);
            PageInfo<Map<String, Object>> pageInfo = new PageInfo<Map<String, Object>>(domainList);
            long total = pageInfo.getTotal();
            resultRecord.setPageIndex(queryItem.getPageIndex());
            resultRecord.setPageSize(queryItem.getPageSize());
            resultRecord.setTotalCount(new Long(total).intValue());
            resultRecord.setNodeList(pageInfo.getList());
            return R.success().put("data", resultRecord);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "服务器错误");
    }

    @ResponseBody
    @RequestMapping(value = "/getDomainGraph")
    public R getDomainGraph(GraphQuery query) {
        try {
            HashMap<String, Object> graphData = kgGraphService.getDomainGraph(query);
            return R.success().put("data", graphData);
        } catch (Exception e) {
            e.printStackTrace();

        }
        return R.error().put("msg", "服务器错误");
    }

    @ResponseBody
    @RequestMapping(value = "/getCypherResult")
    public R getCypherResult(String cypher) {
        try {
            HashMap<String, Object> graphData = neo4jUtil.GetGraphNodeAndShip(cypher);
            return R.success().put("data", graphData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "服务器错误");
    }

    @ResponseBody
    @RequestMapping(value = "/getRelationNodeCount")
    public R getRelationNodeCount(String domain, long nodeId) {
        long totalCount = kgGraphService.getRelationNodeCount(domain, nodeId);
        return R.success().put("data", totalCount);
    }

    @ResponseBody
    @RequestMapping(value = "/createDomain")
    public R createDomain(String domain) {
        try {
            if (StringUtils.isNotBlank(domain)) {
                List<Map<String, Object>> domainItem = knowledgeGraphService.getDomainByName(domain);
                if (domainItem.size() > 0) {
                    return R.error().put("msg", "领域已存在");
                } else {
                    String name = "tc";
                    Map<String, Object> maps = new HashMap<String, Object>();
                    maps.put("name", domain);
                    maps.put("nodeCount", 1);
                    maps.put("shipCount", 0);
                    maps.put("status", 1);
                    maps.put("createUser", name);
                    knowledgeGraphService.saveDomain(maps);// 保存到mysql
                    kgGraphService.createDomain(domain);// 保存到图数据
                }
            }
            return R.success().put("msg", "操作成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/getMoreRelationNode")
    public R getMoreRelationNode(String domain, String nodeId) {
        try {
            if (StringUtils.isNotBlank(domain)) {
                HashMap<String, Object> graphModel = kgGraphService.getMoreRelationNode(domain, nodeId);
                return R.success().put("data", graphModel);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/updateNodeName")
    public R updateNodeName(String domain, String nodeId, String nodename) {
        HashMap<String, Object> graphNodeList = new HashMap<String, Object>();
        try {
            if (StringUtils.isNotBlank(domain)) {
                graphNodeList = kgGraphService.updateNodeName(domain, nodeId, nodename);
                return R.success().put("data", graphNodeList);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/updateCorrdOfNode")
    public R updateCorrdOfNode(String domain, String uuid, Double fx, Double fy) {
        try {
            kgGraphService.updateCorrdOfNode(domain, uuid, fx, fy);
            return R.success().put("msg", "操作成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/createNode")
    public R createNode(GraphNode entity, String domain) {
        HashMap<String, Object> graphNode = new HashMap<String, Object>();
        try {
            graphNode = kgGraphService.createNode(domain, entity);
            return R.success().put("data", graphNode);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/batchCreateNode")
    public R batchCreateNode(String domain, String sourceName, String[] targetNames,
                             String relation) {
        HashMap<String, Object> rss = new HashMap<String, Object>();
        try {
            rss = kgGraphService.batchCreateNode(domain, sourceName, relation, targetNames);
            return R.success().put("data", rss);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/batchCreateChildNode")
    public R batchCreateChildNode(String domain, String sourceId, Integer entityType,
                                  String[] targetNames, String relation) {
        HashMap<String, Object> rss = new HashMap<String, Object>();
        try {
            rss = kgGraphService.batchCreateChildNode(domain, sourceId, entityType, targetNames, relation);
            return R.success().put("data", rss);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/batchCreateSameNode")
    public R batchCreateSameNode(String domain, Integer entityType,
                                 String[] sourceNames) {
        List<HashMap<String, Object>> rss = new ArrayList<HashMap<String, Object>>();
        try {
            rss = kgGraphService.batchCreateSameNode(domain, entityType, sourceNames);
            return R.success().put("data", rss);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/createLink")
    public R createLink(String domain, long sourceId, long targetId, String ship) {
        try {
            HashMap<String, Object> cypherResult = kgGraphService.createLink(domain, sourceId, targetId, ship);
            return R.success().put("data", cypherResult);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/updateLink")
    public R updateLink(String domain, long shipId, String shipName) {
        try {
            HashMap<String, Object> cypherResult = kgGraphService.updateLink(domain, shipId, shipName);
            return R.success().put("data", cypherResult);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/deleteNode")
    public R deleteNode(String domain, long nodeId) {
        try {
            List<HashMap<String, Object>> rList = kgGraphService.deleteNode(domain, nodeId);
            return R.success().put("data", rList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/deleteDomain")
    public R deleteDomain(Integer domainId, String domain) {
        try {
            knowledgeGraphService.deleteDomain(domainId);
            kgGraphService.deleteKGDomain(domain);
            return R.success().put("msg", "操作成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/deleteLink")
    public R deleteLink(String domain, long shipId) {
        try {
            kgGraphService.deleteLink(domain, shipId);
            return R.success().put("msg", "操作成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error().put("msg", "操作失败");
    }

    @ResponseBody
    @RequestMapping(value = "/importGraph")
    public JSONObject importGraph(@RequestParam(value = "file", required = true) MultipartFile file,
                                  HttpServletRequest request, HttpServletResponse response) throws Exception {
        JSONObject res = new JSONObject();
        if (file == null) {
            res.put("code", "500");
            res.put("msg", "请先选择有效的文件");
            return res;
        }
        // 领域不能为空
        String label = request.getParameter("domain");
        if (StringUtils.isNotBlank(label)) {
            res.put("code", "500");
            res.put("msg", "请先选择领域");
            return res;
        }
        List<Map<String, Object>> dataList = getFormatData(file);
        try {
            List<List<String>> list = new ArrayList<>();
            for (Map<String, Object> item : dataList) {
                List<String> lst = new ArrayList<>();
                lst.add(item.get("sourcenode").toString());
                lst.add(item.get("targetnode").toString());
                lst.add(item.get("relationship").toString());
                list.add(lst);
            }
            String savePath = DreamAppConfig.getProfile();
            String csvKey = "tc" + System.currentTimeMillis() + ".csv";
            String csvPath = savePath + csvKey;
            CSVUtil.createCsvFile(list, csvPath);
            String serverUrl = request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
            String csvUrl = "http://" + serverUrl + "/kg/download/" + csvKey;
            //String csvUrl = "https://neo4j.com/docs/cypher-manual/3.5/csv/artists.csv";
            kgGraphService.batchInsertByCSV(label, csvUrl, 0);
            res.put("code", 200);
            res.put("message", "success!");
            return res;
        } catch (Exception e) {
            res.put("code", 500);
            res.put("message", "服务器错误!");
        }
        return res;
    }

    private List<Map<String, Object>> getFormatData(MultipartFile file) throws Exception {
        List<Map<String, Object>> mapList = new ArrayList<>();
        try {
            String fileName = file.getOriginalFilename();
            if (!fileName.endsWith(".csv")) {
                Workbook workbook = null;
                if (ExcelUtil.isExcel2007(fileName)) {
                    workbook = new XSSFWorkbook(file.getInputStream());
                } else {
                    workbook = new HSSFWorkbook(file.getInputStream());
                }
                // 有多少个sheet
                int sheets = workbook.getNumberOfSheets();
                for (int i = 0; i < sheets; i++) {
                    Sheet sheet = workbook.getSheetAt(i);
                    int rowSize = sheet.getPhysicalNumberOfRows();
                    for (int j = 0; j < rowSize; j++) {
                        Row row = sheet.getRow(j);
                        int cellSize = row.getPhysicalNumberOfCells();
                        if (cellSize != 3) continue; //只读取3列
                        row.getCell(0).setCellType(Cell.CELL_TYPE_STRING);
                        Cell cell0 = row.getCell(0);//节点1
                        row.getCell(1).setCellType(Cell.CELL_TYPE_STRING);
                        Cell cell1 = row.getCell(1);//节点2
                        row.getCell(2).setCellType(Cell.CELL_TYPE_STRING);
                        Cell cell2 = row.getCell(2);//关系
                        if (null == cell0 || null == cell1 || null == cell2) {
                            continue;
                        }
                        String sourceNode = cell0.getStringCellValue();
                        String targetNode = cell1.getStringCellValue();
                        String relationShip = cell2.getStringCellValue();
                        if (StringUtils.isBlank(sourceNode) || StringUtils.isBlank(targetNode) || StringUtils.isBlank(relationShip))
                            continue;
                        Map<String, Object> map = new HashMap<String, Object>();
                        map.put("sourcenode", sourceNode);
                        map.put("targetnode", targetNode);
                        map.put("relationship", relationShip);
                        mapList.add(map);
                    }
                }
            } else if (fileName.endsWith(".csv")) {
                List<List<String>> list = CSVUtil.readCsvFile(file);
                for (int i = 0; i < list.size(); i++) {
                    List<String> lst = list.get(i);
                    if (lst.size() != 3) continue;
                    String sourceNode = lst.get(0);
                    String targetNode = lst.get(1);
                    String relationShip = lst.get(2);
                    if (StringUtils.isBlank(sourceNode) || StringUtils.isBlank(targetNode) || StringUtils.isBlank(relationShip))
                        continue;
                    Map<String, Object> map = new HashMap<String, Object>();
                    map.put("sourcenode", sourceNode);
                    map.put("targetnode", targetNode);
                    map.put("relationship", relationShip);
                    mapList.add(map);
                }
            }
        } catch (Exception ex) {
            throw new Exception(ex);
        }
        return mapList;
    }

    @ResponseBody
    @RequestMapping(value = "/exportgraph")
    public JSONObject exportgraph(HttpServletRequest request, HttpServletResponse response) throws Exception {
        JSONObject res = new JSONObject();
        String label = request.getParameter("domain");
        String filePath = DreamAppConfig.getProfile();
        String fileName = UUID.randomUUID() + ".csv";
        String fileUrl = filePath + File.separator + fileName;
        String cypher = String.format(
                "MATCH (n:%s) -[r]->(m:%s) return n.name as source,m.name as target,r.name as relation", label, label);
        List<HashMap<String, Object>> list = neo4jUtil.GetGraphItem(cypher);
        File file = new File(fileUrl);
        try {
            if (!file.exists()) {
                file.createNewFile();
                System.out.println("文件不存在，新建成功！");
            } else {
                System.out.println("文件存在！");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        CsvWriter csvWriter = new CsvWriter(fileUrl, ',', Charset.forName("UTF-8"));
        String[] header = {"source", "target", "relation"};
        csvWriter.writeRecord(header);
        for (HashMap<String, Object> hashMap : list) {
            int colSize = hashMap.size();
            String[] cntArr = new String[colSize];
            cntArr[0] = hashMap.get("source").toString().replace("\"", "");
            cntArr[1] = hashMap.get("target").toString().replace("\"", "");
            cntArr[2] = hashMap.get("relation").toString().replace("\"", "");
            try {
                csvWriter.writeRecord(cntArr);
            } catch (IOException e) {
                System.out.println("CSVUtil->createFile: 文件输出异常" + e.getMessage());
            }
        }
        csvWriter.close();
        String serverUrl = request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
        String csvUrl = serverUrl + "/kg/download/" + fileName;
        res.put("code", 200);
        res.put("csvurl", csvUrl);
        res.put("message", "success!");
        return res;

    }

    // 文件下载相关代码
    @GetMapping(value = "/download/{filename}")
    public String download(@PathVariable("filename") String filename, HttpServletRequest request,
                           HttpServletResponse response) {
        String filePath = DreamAppConfig.getProfile();
        String fileUrl = filePath + File.separator + filename + ".csv";
        if (fileUrl != null) {
            File file = new File(fileUrl);
            if (file.exists()) {
                //response.setContentType("application/force-download");// 设置强制下载不打开
                response.addHeader("Content-Disposition", "attachment;fileName=" + filename + ".csv");// 设置文件名
                byte[] buffer = new byte[1024];
                FileInputStream fis = null;
                BufferedInputStream bis = null;
                try {
                    fis = new FileInputStream(file);
                    bis = new BufferedInputStream(fis);
                    OutputStream os = response.getOutputStream();
                    int i = bis.read(buffer);
                    while (i != -1) {
                        os.write(buffer, 0, i);
                        i = bis.read(buffer);
                    }
                    System.out.println("success");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (bis != null) {
                        try {
                            bis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (fis != null) {
                        try {
                            fis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }

    @ResponseBody
    @RequestMapping(value = "/getNodeImageList")
    public R getNodeImageList(int domainId, int nodeId) {
        try {
            List<Map<String, Object>> images = knowledgeGraphService.getNodeImageList(domainId, nodeId);
            return R.success().put("data", images);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.success().put("msg", "操作成功");
    }

    @ResponseBody
    @RequestMapping(value = "/getNodeContent")
    public R getNodeContent(int domainId, int nodeId) {
        try {
            List<Map<String, Object>> contents = knowledgeGraphService.getNodeContent(domainId, nodeId);
            return R.success().put("data", contents);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.success().put("msg", "操作成功");
    }

    @ResponseBody
    @RequestMapping(value = "/getNodeDetail")
    public R getNodeDetail(int domainId, int nodeId) {
        try {
            Map<String, Object> res = new HashMap<String, Object>();
            res.put("content", "");
            res.put("imageList", new String[]{});
            List<Map<String, Object>> contents = knowledgeGraphService.getNodeContent(domainId, nodeId);
            if (contents != null && contents.size() > 0) {
                res.replace("content", contents.get(0).get("Content"));
            }
            List<Map<String, Object>> images = knowledgeGraphService.getNodeImageList(domainId, nodeId);
            if (images != null && images.size() > 0) {
                res.replace("imageList", images);
            }
            return R.success().put("data", res);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.success().put("msg", "操作成功");
    }

    @ResponseBody
    @RequestMapping(value = "/saveNodeImage")
    public R saveNodeImage(@RequestBody Map<String, Object> params) {
        try {
            String userName = "tc";
            int domainId = (int) params.get("domainId");
            String nodeId = params.get("nodeId").toString();
            String imageList = params.get("imageList").toString();
            List<Map<String, Object>> domainList = knowledgeGraphService.getDomainById(domainId);
            if (domainList != null && domainList.size() > 0) {
                String domainName = domainList.get(0).get("name").toString();
                knowledgeGraphService.deleteNodeImage(domainId, Integer.parseInt(nodeId));
                List<Map> imageItems = JSON.parseArray(imageList, Map.class);
                List<Map<String, Object>> submitItemList = new ArrayList<Map<String, Object>>();
                if (!imageItems.isEmpty()) {
                    for (Map<String, Object> item : imageItems) {
                        String file = item.get("fileurl").toString();
                        int sourcetype = 0;
                        Map<String, Object> sb = new HashMap<String, Object>();
                        sb.put("file", file);
                        sb.put("imagetype", sourcetype);
                        sb.put("domainId", domainId);
                        sb.put("nodeId", nodeId);
                        sb.put("status", 1);
                        sb.put("createUser", userName);
                        sb.put("createTime", DateUtils.getDate());
                        submitItemList.add(sb);
                    }
                }
                if (submitItemList.size() > 0) {
                    knowledgeGraphService.saveNodeImage(submitItemList);
                    // 更新到图数据库,表明该节点有附件,加个标识,0=没有,1=有
                    kgGraphService.updateNodeFileStatus(domainName, Long.parseLong(nodeId), 1);
                } else {
                    kgGraphService.updateNodeFileStatus(domainName, Long.parseLong(nodeId), 0);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.success().put("msg", "操作成功");
    }

    @ResponseBody
    @RequestMapping(value = "/saveNodeContent")
    public R saveNodeContent(@RequestBody Map<String, Object> params) {
        try {
            String userName = "tc";
            int domainId = (int) params.get("domainId");
            String nodeId = params.get("nodeId").toString();
            String content = params.get("content").toString();
            List<Map<String, Object>> domainList = knowledgeGraphService.getDomainById(domainId);
            if (domainList != null && domainList.size() > 0) {
                String domainName = domainList.get(0).get("name").toString();
                // 检查是否存在
                List<Map<String, Object>> items = knowledgeGraphService.getNodeContent(domainId, Integer.parseInt(nodeId));
                if (items != null && items.size() > 0) {
                    Map<String, Object> oldItem = items.get(0);
                    Map<String, Object> item = new HashMap<String, Object>();
                    item.put("domainId", oldItem.get("domainId"));
                    item.put("nodeId", oldItem.get("nodeId"));
                    item.put("content", content);
                    item.put("modifyUser", userName);
                    item.put("modifyTime", DateUtils.getDate());
                    knowledgeGraphService.updateNodeContent(item);

                } else {
                    Map<String, Object> sb = new HashMap<String, Object>();
                    sb.put("content", content);
                    sb.put("domainId", domainId);
                    sb.put("nodeId", nodeId);
                    sb.put("status", 1);
                    sb.put("createUser", userName);
                    sb.put("createTime", DateUtils.getDate());
                    if (sb.size() > 0) {
                        knowledgeGraphService.saveNodeContent(sb);
                    }
                }
                // 更新到图数据库,表明该节点有附件,加个标识,0=没有,1=有
                kgGraphService.updateNodeFileStatus(domainName, Long.parseLong(nodeId), 1);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.success().put("msg", "操作成功");
    }

}
